#include "parser.h"
#include <cassert>

// prog : stmt*
// stmt : decl-stmt | expr-stmt | null-stmt
// null-stmt : ";"
// decl-stmt : "int" identifier ("," identifier (= expr)?)* ";"
// expr-stmt : expr ";"
// expr : assign-expr | add-expr
// assign-expr: identifier "=" expr
// add-expr : mult-expr (("+" | "-") mult-expr)*
// mult-expr : primary-expr (("*" | "/") primary-expr)*
// primary-expr : identifier | number | "(" expr ")"
// number: ([0-9])+
// identifier : (a-zA-Z_)(a-zA-Z0-9_)*

// 解析目标程序
// stmt : decl-stmt | expr-stmt | null-stmt
std::shared_ptr<Program> Parser::ParseProgram()
{
    std::vector<std::shared_ptr<ASTNode>> ExprVec;
    while (token.tokenType != TokenType::eof)
    {
        // 遇到 ; 需要进行消费 token
        // null-stmt
        if (token.tokenType == TokenType::semi)
        {
            Advance();
            continue;
        }
        // decl-stmt
        if (token.tokenType == TokenType::kw_int)
        {
            auto exprs = ParseDeclStmt();
            for (auto expr : exprs)
            {
                ExprVec.push_back(expr);
            }
        }
        else // expr-stmt
        {
            auto expr = ParseExprStmt();
            ExprVec.push_back(expr);
        }
    }
    auto program = std::make_shared<Program>();
    program->ExprVec = std::move(ExprVec);
    return program;
}

// 解析声明
std::vector<std::shared_ptr<ASTNode>> Parser::ParseDeclStmt()
{
    /// int a, b = 3;
    /// int a = 3;
    Consume(TokenType::kw_int);
    CType *baseTy = CType::getIntTy();
    /// a , b = 3;
    /// a = 3;

    std::vector<std::shared_ptr<ASTNode>> astArr;

    /// a, b = 3;
    /// a = 3;
    int i = 0;
    while (token.tokenType != TokenType::semi)
    {
        if (i++ > 0) // if (i++)
        {
            assert(Consume(TokenType::comma));
        }

        /// 变量声明的节点: int a = 3; -> int a; a = 3;
        // a = 3;
        auto variableDecl = sema.SemaVariableDeclNode(token, baseTy); // get a type
        astArr.push_back(variableDecl);
        
        Token tmp = token;
        Consume(TokenType::indentifier);

        // = 3;
        if (token.tokenType == TokenType::equal)
        {
            Token opToken = token;
            Advance();

            // 3;
            auto right = ParseExpr();
            auto left = sema.SemaVariableAccessNode(tmp);
            auto assign = sema.SemaAssignExprNode(left, right, opToken);

            astArr.push_back(assign);
        }
    }

    Advance();

    return astArr;
}

// 解析表达式语句
std::shared_ptr<ASTNode> Parser::ParseExprStmt()
{
    auto expr = ParseExpr();
    Consume(TokenType::semi);
    return expr;
}

// 解析表达式
// expr : assign-expr | add-expr
// assign-expr: identifier "=" expr
// add-expr : mult-expr (("+" | "-") mult-expr)*
std::shared_ptr<ASTNode> Parser::ParseExpr()
{
    lexer.SaveState();
    bool isAssign = false;
    Token tmp = token;
    // a = b;
    if (tmp.tokenType == TokenType::indentifier)
    {
        lexer.NextToken(tmp);
        if (tmp.tokenType == TokenType::equal)
        {
            isAssign = true;
        }
    }
    lexer.RestoreState();
    if (isAssign)
    {
        return ParseAssignExpr();
    }
    // add-expr
    std::shared_ptr<ASTNode> left = ParseTerm();
    while (token.tokenType == TokenType::plus || token.tokenType == TokenType::minus)
    {
        OpCode op;
        if (token.tokenType == TokenType::plus)
        {
            op = OpCode::add;
        }
        else
        {
            op = OpCode::sub;
        }
        Advance();
        auto right = ParseTerm();
        auto binaryExpr = sema.SemaBinaryExprNode(left, right, op);

        left = binaryExpr;
    }
    return left;
}

// 解析赋值表达式
std::shared_ptr<ASTNode> Parser::ParseAssignExpr()
{
    // a = b;
    Token tmp = token;
    Consume(TokenType::indentifier);
    auto expr = sema.SemaVariableAccessNode(tmp);
    Token opToken = token;
    Consume(TokenType::equal);
    return sema.SemaAssignExprNode(expr, ParseExpr(), opToken);
}

// 解析项
std::shared_ptr<ASTNode> Parser::ParseTerm()
{
    std::shared_ptr<ASTNode> left = ParseFactor();

    while (token.tokenType == TokenType::star || token.tokenType == TokenType::slash)
    {
        OpCode op;
        if (token.tokenType == TokenType::star)
        {
            op = OpCode::mul;
        }
        else
        {
            op = OpCode::div;
        }
        Advance();
        auto right = ParseFactor();
        auto binaryExpr = sema.SemaBinaryExprNode(left, right, op);

        left = binaryExpr;
    }
    return left;
}

// 解析因子
std::shared_ptr<ASTNode> Parser::ParseFactor()
{
    if (token.tokenType == TokenType::l_parent)
    {
        Advance();
        auto expr = ParseExpr();
        assert(Expect(TokenType::r_parent));
        Advance();
        return expr;
    }
    else if (token.tokenType == TokenType::indentifier)
    {
        auto variableAccessExpr = sema.SemaVariableAccessNode(token);
        Advance();
        return variableAccessExpr;
    }
    else
    {
        Expect(TokenType::number);
        auto factorExpr = sema.SemaNumberExprNode(token, token.type);
        Advance();
        return factorExpr;
    }
}

/// 消耗 token 函数
bool Parser::Expect(TokenType tokenType)
{
    if (token.tokenType == tokenType)
        return true;
    GetDiagEngine().Report(llvm::SMLoc::getFromPointer(token.ptr),
                           diag::err_expected,
                           Token::GetSpellingText(tokenType),
                           llvm::StringRef(token.ptr, token.length));
    return false;
}

bool Parser::Consume(TokenType tokenType)
{
    if (Expect(tokenType))
    {
        Advance();
        return true;
    }
    return false;
}

bool Parser::Advance()
{
    lexer.NextToken(token);
    return true;
}